package com.jiyinit.web.core.mobile.controller;

import com.jiyinit.core.framework.base.entity.ResponseDto;
import com.jiyinit.core.framework.base.util.Check;
import com.jiyinit.core.framework.base.util.JsonEntityTransform;
import com.jiyinit.web.core.common.config.PropertyPlaceholderConfigurer;
import com.jiyinit.web.core.mobile.dto.MobileFileRequest;
import com.jiyinit.web.core.mobile.dto.MobileFileResponse;
import com.jiyinit.web.core.mobile.enums.FileTypeEnum;
import com.jiyinit.web.core.mobile.util.FilesUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import sun.misc.BASE64Decoder;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by user1 on 2019/1/11.
 */
@Controller
@RequestMapping("mobile/fileupload")
public class MobileFileUploadController {

    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(MobileFileUploadController.class);

    @Resource(name = "multipartResolver")
    private MultipartResolver multipartResolver;

    /**
     * 上传文件接口
     *
     * @param request
     * @param response
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
    public ResponseEntity<ResponseDto> fileUpload(HttpServletRequest request, HttpServletResponse response) {
        long startTime = System.currentTimeMillis();
        MobileFileRequest fileRequest = getMobileFileRequest(request, MobileFileRequest.class);
        LOGGER.info("移动端上传文件接口: mobile/fileupload/uploadFile, 文件名称{}", fileRequest.getFileName());
        MobileFileResponse resultVo = new MobileFileResponse();
        try {
            resultVo = saveFiles(request, fileRequest);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("error: {}", e.getMessage());
            resultVo.setResult("error");
            resultVo.setServerUrl("");
            return new ResponseEntity<>(ResponseDto.responseFail("系统异常, 上传失败!"), HttpStatus.OK);
        }
        long endTime  = System.currentTimeMillis();
        LOGGER.info("本次上传文件耗时----->{}ms", (startTime - endTime));
        return new ResponseEntity<>(ResponseDto.responseOK(resultVo), HttpStatus.OK);
    }

    /**
     * 保存文件
     * @param request
     * @return
     */
/*
    private MobileFileResponse saveFile(HttpServletRequest request, MobileFileRequest fileRequest) throws IOException {
        String fileUrl = (String) PropertyPlaceholderConfigurer.getContextProperty("SAVE_FILE_URL");//获取保存目录
        String oldName = fileRequest.getFileName();                                         //文件原名称
        String suffix = oldName.substring(oldName.lastIndexOf("."), oldName.length());      //文件后缀
        String format = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String newName = format + UUID.randomUUID().toString().substring(6, 10) + "_" + fileRequest.getFileType()+suffix;//文件新名称
        String realUrl = request.getSession().getServletContext().getRealPath("") + "/" + fileUrl + newName;//文件的绝对路径

        BASE64Decoder decoder = new BASE64Decoder();
        byte[] decodeBytes = decoder.decodeBuffer(fileRequest.getFileData());
        LOGGER.info("保存文件类型: {}, 文件位置: {}, 文件名称: {}, 文件大小: {} ",
                FileTypeEnum.getName(fileRequest.getFileType()), realUrl, newName, decodeBytes.length);
        for (int i = 0; i < decodeBytes.length; ++i) {
            if (decodeBytes[i] < 0) {// 调整异常数据
                decodeBytes[i] += 256;
            }
        }

        File file = new File(realUrl);
        FilesUtil.createDirectoryAndFile(file);

        FileOutputStream fos = new FileOutputStream(file);
        fos.write(decodeBytes);
        fos.flush();
        fos.close();
        MobileFileResponse resultVo = new MobileFileResponse();
        resultVo.setResult("success");
        resultVo.setServerUrl(fileUrl+newName);
        return resultVo;
    }
*/

    /**
     * 保存文件(不限制大小)
     * @param request
     * @param fileRequest
     * @return
     * @throws IOException
     */
    public MobileFileResponse saveFiles(HttpServletRequest request, MobileFileRequest fileRequest) throws IOException {
        String line = File.separator;
        MobileFileResponse resultVo = new MobileFileResponse();
        List<MultipartFile> fileList = getMultipartFileList(request);
        String fileType = fileRequest.getFileType();

        for (MultipartFile file : fileList) {
            String fileUrl = FileTypeEnum.getSaveUrl(fileType); //获取保存目录, 不传fileType时有一个默认存储路径
            String oldName = file.getOriginalFilename();                                  //文件原名称
            String suffix = oldName.substring(oldName.lastIndexOf("."), oldName.length());//文件后缀
            String format = new SimpleDateFormat("yyyyMMdd_HHmmss_").format(new Date());
            String newName = format + UUID.randomUUID().toString().substring(6, 10) + suffix;//文件新名称
            String realUrl = request.getSession().getServletContext().getRealPath("") + line + fileUrl + newName;//文件的绝对路径

            LOGGER.info("保存文件类型: {}, 文件位置: {}, 文件名称: {}, 文件大小: {} ",
                    fileUrl, realUrl, newName, file.getSize());
            File dest = new File(realUrl);
            FilesUtil.createDirectoryAndFile(dest);

            file.transferTo(dest);

            resultVo.setResult("success");
            resultVo.setServerUrl(fileUrl + newName);
            return resultVo;
        }

        resultVo.setResult("error");
        resultVo.setServerUrl("");
        return resultVo;
    }


    /**
     * json转换请求类
     * @param request
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T convertRequest(HttpServletRequest request, Class<T> clazz) {
        String request_json = request.getParameter("request_json");
        return (T) JsonEntityTransform.json2Object(request_json, clazz);
    }

    /**
     * 获取 向request中赋值
     * @param req
     * @return
     */
    private <T> T getMobileFileRequest(ServletRequest req, Class<T> clazz){
        String enctype = req.getContentType();
        if (StringUtils.isNotBlank(enctype) && enctype.contains("multipart/form-data")){
            MultipartHttpServletRequest multipartRequest = multipartResolver.resolveMultipart((HttpServletRequest) req);
            Map<String, String[]> map = multipartRequest.getParameterMap();
            T obj = null;
            try {
                obj = clazz.newInstance();
                Field[] fields = clazz.getDeclaredFields();
                Set<String> keySet = map.keySet();
                for (int j = 0; j < fields.length; j++) {
                    Field field = fields[j];
                    field.setAccessible(true);
                    String fname = field.getName();
                    if(keySet.contains(fname)){
                        field.set(obj, map.get(fname)[0]);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                LOGGER.error("error: {}", e.getMessage());
            }
            return obj;
            // 返回 MultipartHttpServletRequest 用于获取 multipart/form-data 方式提交的请求中 上传的参数
            //return multipartResolver.resolveMultipart((HttpServletRequest) req);
        }else{
            HttpServletRequest request = (HttpServletRequest) req;
            String request_json = request.getParameter("request_json");
            return (T) JsonEntityTransform.json2Object(request_json, clazz);
        }
    }


    /**
     * 获取当前请求中的文件列表
     *
     * @param request
     * @return
     */
    private static List<MultipartFile> getMultipartFileList(HttpServletRequest request) {
        List<MultipartFile> files = new ArrayList<MultipartFile>();
        try {
            CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
            if (request instanceof MultipartHttpServletRequest) {
                // 将request变成多部分request
                MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
                Iterator<String> iter = multiRequest.getFileNames();
                // 检查form中是否有enctype="multipart/form-data"
                if (multipartResolver.isMultipart(request) && iter.hasNext()) {
                    // 获取multiRequest 中所有的文件名
                    while (iter.hasNext()) {
                        // 一次遍历所有文件
                        // MultipartFile file =
                        // multiRequest.getFile(iter.next().toString());
                        // if (file != null) {
                        // files.add(file);
                        // }
                        // 适配名字重复的文件
                        List<MultipartFile> fileRows = multiRequest.getFiles(iter.next());
                        if (fileRows != null && fileRows.size() != 0) {
                            for (MultipartFile file : fileRows) {
                                if (file != null && !file.isEmpty()) {
                                    files.add(file);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("解析MultipartRequest错误", e);
        }
        return files;
    }

}
